<?php

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

namespace common\components\wechat\models;

use Yii;
use yii\helpers\ArrayHelper;

/**
 * 统一下单输入对象
 * @author emhome
 */
class UnifiedOrder extends BasePayment {

    /**
     * 商品或支付单简要描述
     * @param string $body 
     */
    public $body;

    /**
     * 微信支付分配的终端设备号
     * 商户自定义
     * @param String(32) $device_info 
     * 
     */
    public $device_info;

    /**
     * 商品名称明细列表
     * @param string $detail 
     */
    public $detail;

    /**
     * 附加数据，在查询API和支付通知中原样返回，该字段主要用于商户携带订单的自定义数据
     * @param string $attach 
     */
    public $attach;

    /**
     * 商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号
     * @param string $out_trade_no 
     */
    public $out_trade_no;

    /**
     * 订单总金额，只能为整数，详见支付金额
     * @param string $total_fee 
     */
    public $total_fee;

    /**
     * 符合ISO 4217标准的三位字母代码，默认人民币：CNY，其他值列表详见货币类型
     * @param string $fee_type 
     * */
    public $fee_type = 'CNY';

    /**
     * APP和网页支付提交用户端ip，Native支付填调用微信支付API的机器IP。
     * @param string $spbill_create_ip 
     */
    public $spbill_create_ip;

    /**
     * 订单生成时间
     * 格式为yyyyMMddHHmmss，如2009年12月25日9点10分10秒表示为20091225091010
     * @param string $time_start 
     */
    public $time_start;

    /**
     * 订单失效时间
     * 格式为yyyyMMddHHmmss，如2009年12月27日9点10分10秒表示为20091227091010
     * @param string $time_expire 
     */
    public $time_expire;

    /**
     * 商品标记
     * 代金券或立减优惠功能的参数，说明详见代金券或立减优惠
     * @param string $goods_tag 
     */
    public $goods_tag;

    /**
     * 接收微信支付异步通知回调地址
     * @param string $notify_url 
     */
    public $notify_url;

    /**
     * 取值如下：JSAPI|NATIVE|APP|MWEB
     * @param string $trade_type 
     */
    public $trade_type;

    /**
     * 商户自行定义的商品ID
     * 扫码支付时此ID为二维码中包含的商品ID
     * trade_type=NATIVE
     * 此参数必传
     * @param string $product_id 
     */
    public $product_id;

    /**
     * trade_type=JSAPI，此参数必传，用户在商户appid下的唯一标识。下单前需要调用【网页授权获取用户信息】接口获取到用户的Openid。 
     * @param string $openid 
     */
    public $openid;

    /**
     * no_credit--指定不能使用信用卡支付
     * @param string $limit_pay 
     */
    public $limit_pay;

    /**
     * 交易中心统一下单请求参数校验
     * @inheritdoc
     */
    public function rules() {
        $rules = [
            [['body', 'out_trade_no', 'total_fee', 'trade_type'], 'required'],
            //校验trade_type
            ['trade_type', 'in', 'range' => ['JSAPI', 'NATIVE', 'APP', 'MWEB']],
            //JSAPI支付时校验openid
            ['spbill_create_ip', 'validateSpbillCreateIp'],
            ['notify_url', 'validateNotifyUrl'],
            ['total_fee', 'number'],
            ['fee_type', 'string', 'max' => 16],
            [['product_id', 'device_info', 'goods_tag', 'limit_pay'], 'string', 'max' => 32],
            [['attach'], 'string', 'max' => 127],
            [['body', 'out_trade_no', 'openid'], 'string', 'max' => 128],
            ['detail', 'string', 'max' => 6000],
            [['time_start', 'time_expire'], 'date', 'format' => 'yyyyMMddHHmmss'],
            //校验总价格
            ['total_fee', 'compare', 'compareValue' => 0, 'operator' => '>'],
            ['notify_url', 'string', 'max' => 256],
            //JSAPI支付时校验openid
            ['openid', 'validateOpenid'],
            //NATIVE支付时校验product_id
            ['product_id', 'validateProductid'],
        ];

        return ArrayHelper::merge(parent::rules(), $rules);
    }

    /**
     * Validates the APPID.
     * 验证app_id是否为该商户本身
     *
     * @param string $attribute the attribute currently being validated
     */
    public function validateSpbillCreateIp($attribute) {
        if (!$this->hasErrors()) {
            if (!$this->$attribute) {
                $this->$attribute = Yii::$app->request->userIP;
            }
        }
    }

    /**
     * Validates the signature.
     * 校验请求的签名
     *
     * @param string $attribute the attribute currently being validated
     */
    public function validateNotifyUrl($attribute) {
        if (!$this->hasErrors()) {
            if (!$this->$attribute) {
                $this->$attribute = $this->model->paymentConfig['notify_url'];
            }
        }
    }

    /**
     * Validates the signature.
     * 校验请求的签名
     *
     * @param string $attribute the attribute currently being validated
     */
    public function validateOpenid($attribute) {
        if (!$this->hasErrors()) {
            if ($this->trade_type == self::TRADE_TYPE_JSAPI && !$this->$attribute) {
                $this->addError($attribute, '缺少openid！');
            }
        }
    }

    /**
     * Validates the signature.
     * 校验请求的签名
     *
     * @param string $attribute the attribute currently being validated
     */
    public function validateProductid($attribute) {
        if (!$this->hasErrors()) {
            if ($this->trade_type == self::TRADE_TYPE_NATIVE && !$this->$attribute) {
                $this->addError($attribute, '缺少productid！');
            }
        }
    }

    /**
     * 统一下单
     * 
     * @see WxPayUnifiedOrder
     * @need out_trade_no|body|total_fee|trade_type 必填
     * @ignore appid|mchid|spbill_create_ip|nonce_str 不需要填入
     * 
     * @param WxPayUnifiedOrder $inputObj
     * @param int $timeOut
     * @throws WxPayException
     * @return 成功时返回，其他抛异常
     */
    public function save() {
        if (!$this->validate()) {
            return false;
        }

        $url = self::WECHAT_PAYMENT_URL . self::UNIFIED_ORDER_URL;
        //检测必填参数
        //签名
        $this->generateSign($this->sign);
        $xml = $this->toXml();
        $timeOut = 6;
        $startTimeStamp = self::getMillisecond(); //请求开始时间
        $response = self::postHttp($xml, $url, false, $timeOut);

        return $this->responseData($response);
    }

}
